/*
 * Copyright 2004-2014 SmartBear Software
 *
 * Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent
 * versions of the EUPL (the "Licence");
 * You may not use this work except in compliance with the Licence.
 * You may obtain a copy of the Licence at:
 *
 * http://ec.europa.eu/idabc/eupl
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the Licence is
 * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the Licence for the specific language governing permissions and limitations
 * under the Licence.
*/

package com.eviware.soapui.impl.support.panels;

import com.eviware.soapui.SoapUI;
import com.eviware.soapui.config.CredentialsConfig;
import com.eviware.soapui.impl.support.AbstractHttpRequest;
import com.eviware.soapui.impl.support.AbstractHttpRequestInterface;
import com.eviware.soapui.impl.support.EndpointsComboBoxModel;
import com.eviware.soapui.impl.support.actions.ShowOnlineHelpAction;
import com.eviware.soapui.impl.support.components.ModelItemXmlEditor;
import com.eviware.soapui.impl.support.components.RequestMessageXmlEditor;
import com.eviware.soapui.impl.support.components.ResponseMessageXmlEditor;
import com.eviware.soapui.impl.wsdl.WsdlProject;
import com.eviware.soapui.impl.wsdl.submit.transports.http.HttpResponse;
import com.eviware.soapui.model.ModelItem;
import com.eviware.soapui.model.iface.Attachment;
import com.eviware.soapui.model.iface.Request.SubmitException;
import com.eviware.soapui.model.iface.Submit;
import com.eviware.soapui.model.iface.Submit.Status;
import com.eviware.soapui.model.iface.SubmitContext;
import com.eviware.soapui.model.iface.SubmitListener;
import com.eviware.soapui.model.support.ModelSupport;
import com.eviware.soapui.settings.UISettings;
import com.eviware.soapui.support.StringUtils;
import com.eviware.soapui.support.UISupport;
import com.eviware.soapui.support.actions.ChangeSplitPaneOrientationAction;
import com.eviware.soapui.support.components.Inspector;
import com.eviware.soapui.support.components.JEditorStatusBarWithProgress;
import com.eviware.soapui.support.components.JXToolBar;
import com.eviware.soapui.support.editor.inspectors.AbstractXmlInspector;
import com.eviware.soapui.support.editor.inspectors.auth.AuthInspectorFactory;
import com.eviware.soapui.support.editor.views.xml.source.XmlSourceEditorView;
import com.eviware.soapui.support.editor.views.xml.source.XmlSourceEditorView.JEditorStatusBarTargetProxy;
import com.eviware.soapui.support.editor.xml.XmlDocument;
import com.eviware.soapui.support.swing.SoapUISplitPaneUI;
import com.eviware.soapui.ui.support.ModelItemDesktopPanel;
import org.apache.log4j.Logger;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.ComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JToggleButton;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

/**
 * Abstract DesktopPanel for HttpRequests
 *
 * @author Ole.Matzura
 */

public abstract class AbstractHttpRequestDesktopPanel<T extends ModelItem, T2 extends AbstractHttpRequestInterface<?>>
        extends ModelItemDesktopPanel<T> implements SubmitListener {
    private final static Logger log = Logger.getLogger(AbstractHttpRequestDesktopPanel.class);
    public static final String END_POINT_COMBO_BOX = "EndPointComboBox";

    protected EndpointsComboBoxModel endpointsModel;

    private JButton submitButton;
    private JButton cancelButton;
    private JLabel lockIcon;
    private JComponent endpointComponent;
    private JEditorStatusBarWithProgress statusBar;
    private JButton splitButton;
    private Submit submit;
    private JSplitPane requestSplitPane;
    private MoveFocusAction moveFocusAction;
    private ClosePanelAction closePanelAction = new ClosePanelAction();
    private T2 request;

    private ModelItemXmlEditor<?, ?> requestEditor;
    private ModelItemXmlEditor<?, ?> responseEditor;

    private JTabbedPane requestTabs;
    private JPanel requestTabPanel;
    private JToggleButton tabsButton;

    private boolean responseHasFocus;
    private SubmitAction submitAction;
    private boolean hasClosed;

    public AbstractHttpRequestDesktopPanel(T modelItem, T2 request) {
        super(modelItem);

        this.request = request;

        init(request);

        try {
            // required to avoid deadlock in UI when opening attachments inspector
            if (request.getAttachmentCount() > 0 && request.getOperation() != null) {
                request.getOperation().getInterface().getDefinitionContext().loadIfNecessary();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void setEndpointsModel(T2 request) {
        this.endpointsModel = new EndpointsComboBoxModel(request);
    }

    public ComboBoxModel getEndpointsModel() {
        return endpointsModel;
    }

    public void setEndpointComponent(JComponent endpointComponent) {
        this.endpointComponent = endpointComponent;
    }

    public JButton getCancelButton() {
        return cancelButton;
    }

    public JButton getSplitButton() {
        return splitButton;
    }

    public JToggleButton getTabsButton() {
        return tabsButton;
    }

    protected void init(T2 request) {
        initializeFields();
        setEndpointsModel(request);

        request.addSubmitListener(this);
        request.addPropertyChangeListener(this);

        add(buildContent(), BorderLayout.CENTER);
        add(buildToolbar(), BorderLayout.NORTH);
        add(buildStatusLabel(), BorderLayout.SOUTH);

        //TODO: remove this when other hardcoded sizes are gone
        setPreferredSize(new Dimension(1200, 800));

        addFocusListener(new FocusAdapter() {

            @Override
            public void focusGained(FocusEvent e) {
                if (requestTabs.getSelectedIndex() == 1 || responseHasFocus) {
                    responseEditor.requestFocusInWindow();
                } else {
                    requestEditor.requestFocusInWindow();
                }
            }
        });
    }

    protected void initializeFields() {

    }

    public final T2 getRequest() {
        return request;
    }

    public final ModelItemXmlEditor<?, ?> getRequestEditor() {
        return requestEditor;
    }

    public final ModelItemXmlEditor<?, ?> getResponseEditor() {
        return responseEditor;
    }

    public Submit getSubmit() {
        return submit;
    }

    protected JComponent buildStatusLabel() {
        statusBar = new JEditorStatusBarWithProgress();
        statusBar.setBorder(BorderFactory.createEmptyBorder(1, 0, 0, 0));

        return statusBar;
    }

    public JEditorStatusBarWithProgress getStatusBar() {
        return statusBar;
    }

    protected JComponent buildContent() {
        requestSplitPane = UISupport.createHorizontalSplit();
        requestSplitPane.setResizeWeight(0.5);
        requestSplitPane.setBorder(null);

        submitAction = new SubmitAction();
        submitButton = createActionButton(submitAction, true);
        submitButton.setEnabled(request.getEndpoint() != null && request.getEndpoint().trim().length() > 0);

        cancelButton = createActionButton(new CancelAction(), false);
        splitButton = createActionButton(new ChangeSplitPaneOrientationAction(requestSplitPane), true);

        tabsButton = new JToggleButton(new ChangeToTabsAction());
        tabsButton.setPreferredSize(UISupport.TOOLBAR_BUTTON_DIMENSION);

        moveFocusAction = new MoveFocusAction();

        requestEditor = buildRequestEditor();
        responseEditor = buildResponseEditor();

        requestTabs = new JTabbedPane();
        requestTabs.addChangeListener(new ChangeListener() {

            public void stateChanged(ChangeEvent e) {
                SwingUtilities.invokeLater(new Runnable() {

                    public void run() {
                        int ix = requestTabs.getSelectedIndex();
                        if (ix == 0) {
                            requestEditor.requestFocus();
                        } else if (ix == 1 && responseEditor != null) {
                            responseEditor.requestFocus();
                        }
                    }
                });
            }
        });

        requestTabPanel = UISupport.createTabPanel(requestTabs, true);

        if (request.getSettings().getBoolean(UISettings.START_WITH_REQUEST_TABS)) {
            requestTabs.addTab("Request", requestEditor);
            if (responseEditor != null) {
                requestTabs.addTab("Response", responseEditor);
            }
            splitButton.setEnabled(false);
            tabsButton.setSelected(true);

            return requestTabPanel;
        } else {
            requestSplitPane.setTopComponent(requestEditor);
            requestSplitPane.setBottomComponent(responseEditor);
            requestSplitPane.setDividerLocation(0.5);
            return requestSplitPane;
        }
    }

    public SubmitAction getSubmitAction() {
        return submitAction;
    }

    protected abstract ModelItemXmlEditor<?, ?> buildResponseEditor();

    protected abstract ModelItemXmlEditor<?, ?> buildRequestEditor();

    protected JComponent buildToolbar() {
        JPanel endpointPanel = buildEndpointPanel();

        JXToolBar toolbar = UISupport.createToolbar();
        toolbar.add(submitButton);

        insertButtons(toolbar);

        toolbar.add(cancelButton);

        if (endpointComponent != null) {
            toolbar.addSeparator();

            toolbar.add(endpointPanel);
        }

        toolbar.add(Box.createHorizontalGlue());
        toolbar.add(tabsButton);
        toolbar.add(splitButton);
        toolbar.add(UISupport.createToolbarButton(new ShowOnlineHelpAction(getHelpUrl())));

        return toolbar;
    }

    protected JComponent buildEndpointComponent() {
        final JComboBox endpointCombo = new JComboBox(endpointsModel);
        endpointCombo.setEditable(true);
        endpointCombo.setName(END_POINT_COMBO_BOX);
        Document textFieldDocument = ((JTextComponent) endpointCombo.getEditor().getEditorComponent()).getDocument();
        endpointsModel.listenToChangesIn(textFieldDocument);
        endpointCombo.addPropertyChangeListener(this);
        endpointCombo.setToolTipText(endpointsModel.getSelectedItem().toString());

        return UISupport.addTooltipListener(endpointCombo, "- no endpoint set for request -");
    }

    public void propertyChange(PropertyChangeEvent evt) {
        if (evt.getPropertyName().equals(AbstractHttpRequest.ENDPOINT_PROPERTY)) {
            submitButton.setEnabled(submit == null && StringUtils.hasContent(request.getEndpoint()));
        }

        super.propertyChange(evt);
    }

    public JButton getSubmitButton() {
        return submitButton;
    }

    protected abstract String getHelpUrl();

    protected abstract void insertButtons(JXToolBar toolbar);

    public void setEnabled(boolean enabled) {
        if (endpointComponent != null) {
            WsdlProject project = (WsdlProject) ModelSupport.getModelItemProject(getModelItem());
            if (project.isEnvironmentMode()) {
                endpointComponent.setEnabled(false);
            } else {
                endpointComponent.setEnabled(true);
            }

        }

        requestEditor.setEditable(enabled);
        if (responseEditor != null) {
            responseEditor.setEditable(enabled);
        }

        submitButton.setEnabled(enabled && request.hasEndpoint());

        statusBar.setIndeterminate(!enabled);
    }

    protected void buildLockIcon() {
        lockIcon = new JLabel(UISupport.createImageIcon("/lock.png"));
        lockIcon.setVisible(isAuthActivated(getRequest().getAuthType()));
        lockIcon.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        lockIcon.addMouseListener(new MouseAdapter() {
                                      @Override
                                      public void mouseClicked(MouseEvent e) {
                                          Inspector inspector = getRequestEditor().getInspector(AuthInspectorFactory.INSPECTOR_ID);
                                          if (inspector != null) {
                                              ((AbstractXmlInspector) inspector).showInPanel();
                                          }
                                      }
                                  }
        );
        getRequest().addPropertyChangeListener(AbstractHttpRequest.SELECTED_AUTH_PROFILE_PROPERTY_NAME, new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                lockIcon.setVisible(isAuthActivated((String) evt.getNewValue()));
            }
        });

    }

    protected boolean isAuthActivated(String authType) {
        return authType != null && !(authType.equals(CredentialsConfig.AuthType.NO_AUTHORIZATION.toString()));
    }

    protected JPanel buildEndpointPanel() {
        JComponent endpointCombo = buildEndpointComponent();
        setEndpointComponent(endpointCombo);

        JPanel comboBoxPanel = new JPanel(new BorderLayout(0, 0));
        buildLockIcon();
        comboBoxPanel.add(lockIcon, BorderLayout.WEST);
        if (endpointComponent != null) {
            comboBoxPanel.add(endpointCombo, BorderLayout.CENTER);
        }
        return comboBoxPanel;
    }

    protected JLabel getLockIcon() {
        return lockIcon;
    }

    public abstract class AbstractHttpRequestMessageEditor<T3 extends XmlDocument> extends
            RequestMessageXmlEditor<T2, T3> {
        private InputAreaFocusListener inputAreaFocusListener;
        private RSyntaxTextArea inputArea;

        public AbstractHttpRequestMessageEditor(T3 document) {
            super(document, request);

            XmlSourceEditorView<?> editor = getSourceEditor();
            if (editor != null) {
                inputArea = editor.getInputArea();

                if (UISupport.isMac()) {
                    inputArea.getInputMap().put(KeyStroke.getKeyStroke("meta ENTER"), submitButton.getAction());
                    inputArea.getInputMap().put(KeyStroke.getKeyStroke("meta X"), cancelButton.getAction());
                    inputArea.getInputMap().put(KeyStroke.getKeyStroke("ctrl meta TAB"), moveFocusAction);
                    inputArea.getInputMap().put(KeyStroke.getKeyStroke("ctrl F4"), closePanelAction);
                } else {
                    inputArea.getInputMap().put(KeyStroke.getKeyStroke("alt ENTER"), submitButton.getAction());
                    inputArea.getInputMap().put(KeyStroke.getKeyStroke("alt X"), cancelButton.getAction());
                    inputArea.getInputMap().put(KeyStroke.getKeyStroke("ctrl alt TAB"), moveFocusAction);
                    inputArea.getInputMap().put(KeyStroke.getKeyStroke("ctrl F4"), closePanelAction);
                }

                inputAreaFocusListener = new InputAreaFocusListener(editor);
                inputArea.addFocusListener(inputAreaFocusListener);
            }

            submitButton.setMnemonic(KeyEvent.VK_ENTER);

        }

        @Override
        public void release() {
            super.release();
            if (inputArea != null) {
                inputArea.removeFocusListener(inputAreaFocusListener);
            }
        }
    }

    public abstract class AbstractHttpResponseMessageEditor<T3 extends XmlDocument> extends
            ResponseMessageXmlEditor<T2, T3> {
        private RSyntaxTextArea inputArea;
        private ResultAreaFocusListener resultAreaFocusListener;

        public AbstractHttpResponseMessageEditor(T3 document) {
            super(document, request);

            XmlSourceEditorView<?> editor = getSourceEditor();

            inputArea = editor.getInputArea();
            if (inputArea != null) {
                resultAreaFocusListener = new ResultAreaFocusListener(editor);
                inputArea.addFocusListener(resultAreaFocusListener);

                if (UISupport.isMac()) {
                    inputArea.getInputMap().put(KeyStroke.getKeyStroke("meta ENTER"), submitButton.getAction());
                    inputArea.getInputMap().put(KeyStroke.getKeyStroke("meta X"), cancelButton.getAction());
                    inputArea.getInputMap().put(KeyStroke.getKeyStroke("ctrl meta TAB"), moveFocusAction);
                    inputArea.getInputMap().put(KeyStroke.getKeyStroke("ctrl F4"), closePanelAction);
                } else {
                    inputArea.getInputMap().put(KeyStroke.getKeyStroke("alt ENTER"), submitButton.getAction());
                    inputArea.getInputMap().put(KeyStroke.getKeyStroke("alt X"), cancelButton.getAction());
                    inputArea.getInputMap().put(KeyStroke.getKeyStroke("ctrl alt TAB"), moveFocusAction);
                    inputArea.getInputMap().put(KeyStroke.getKeyStroke("ctrl F4"), closePanelAction);
                }
            }

            submitButton.setMnemonic(KeyEvent.VK_ENTER);

        }

        @Override
        public void release() {
            super.release();

            if (inputArea != null) {
                inputArea.removeFocusListener(resultAreaFocusListener);
            }
        }
    }

    protected final class InputAreaFocusListener implements FocusListener {
        private final XmlSourceEditorView<?> sourceEditor;

        public InputAreaFocusListener(XmlSourceEditorView<?> editor) {
            this.sourceEditor = editor;
        }

        public void focusGained(FocusEvent e) {
            responseHasFocus = false;

            statusBar.setTarget(new JEditorStatusBarTargetProxy(sourceEditor.getInputArea()));
            if (!splitButton.isEnabled()) {
                requestTabs.setSelectedIndex(0);
                return;
            }

            if (getModelItem().getSettings().getBoolean(UISettings.NO_RESIZE_REQUEST_EDITOR)) {
                return;
            }

            // dont resize if split has been dragged
            if (requestSplitPane.getUI() instanceof SoapUISplitPaneUI
                    && ((SoapUISplitPaneUI) requestSplitPane.getUI()).hasBeenDragged()) {
                return;
            }

            int pos = requestSplitPane.getDividerLocation();
            if (pos >= 600) {
                return;
            }
            if (requestSplitPane.getMaximumDividerLocation() > 700) {
                requestSplitPane.setDividerLocation(600);
            } else {
                requestSplitPane.setDividerLocation(0.8);
            }
        }

        public void focusLost(FocusEvent e) {
        }
    }

    protected final class ResultAreaFocusListener implements FocusListener {
        private final XmlSourceEditorView<?> sourceEditor;

        public ResultAreaFocusListener(XmlSourceEditorView<?> editor) {
            this.sourceEditor = editor;
        }

        public void focusGained(FocusEvent e) {
            responseHasFocus = true;

            statusBar.setTarget(new JEditorStatusBarTargetProxy(sourceEditor.getInputArea()));
            if (!splitButton.isEnabled()) {
                requestTabs.setSelectedIndex(1);
                return;
            }

            if (request.getSettings().getBoolean(UISettings.NO_RESIZE_REQUEST_EDITOR)) {
                return;
            }

            // dont resize if split has been dragged or result is empty
            if (requestSplitPane.getUI() instanceof SoapUISplitPaneUI
                    && ((SoapUISplitPaneUI) requestSplitPane.getUI()).hasBeenDragged() || request.getResponse() == null) {
                return;
            }

            int pos = requestSplitPane.getDividerLocation();
            int maximumDividerLocation = requestSplitPane.getMaximumDividerLocation();
            if (pos + 600 < maximumDividerLocation) {
                return;
            }

            if (maximumDividerLocation > 700) {
                requestSplitPane.setDividerLocation(maximumDividerLocation - 600);
            } else {
                requestSplitPane.setDividerLocation(0.2);
            }
        }

        public void focusLost(FocusEvent e) {
        }
    }

    public class SubmitAction extends AbstractAction {
        public SubmitAction() {
            putValue(Action.SMALL_ICON, UISupport.createImageIcon("/submit_request.gif"));
            putValue(Action.SHORT_DESCRIPTION, "Submit request to specified endpoint URL (Alt-Enter)");
            putValue(Action.ACCELERATOR_KEY, UISupport.getKeyStroke("alt ENTER"));
        }

        public void actionPerformed(ActionEvent e) {
            onSubmit();
        }
    }

    protected abstract Submit doSubmit() throws SubmitException;

    private class CancelAction extends AbstractAction {
        public CancelAction() {
            super();
            putValue(Action.SMALL_ICON, UISupport.createImageIcon("/cancel_request.gif"));
            putValue(Action.SHORT_DESCRIPTION, "Aborts ongoing request");
            putValue(Action.ACCELERATOR_KEY, UISupport.getKeyStroke("alt X"));
        }

        public void actionPerformed(ActionEvent e) {
            onCancel();
        }
    }

    private class ClosePanelAction extends AbstractAction {
        public void actionPerformed(ActionEvent e) {
            SoapUI.getDesktop().closeDesktopPanel(getModelItem());
        }
    }

    private class MoveFocusAction extends AbstractAction {
        public void actionPerformed(ActionEvent e) {
            if (requestEditor.hasFocus()) {
                responseEditor.requestFocus();
            } else {
                requestEditor.requestFocus();
            }
        }
    }

    public boolean beforeSubmit(Submit submit, SubmitContext context) {
        if (submit.getRequest() != request) {
            return true;
        }

        if (getModelItem().getSettings().getBoolean(UISettings.AUTO_VALIDATE_REQUEST)) {
            boolean result = requestEditor.saveDocument(true);
            if (!result && getModelItem().getSettings().getBoolean(UISettings.ABORT_ON_INVALID_REQUEST)) {
                statusBar.setInfo("Cancelled request due to invalid content");
                return false;
            }
        } else {
            if (requestEditor != null) {
                requestEditor.saveDocument(false);
            }
        }

        setEnabled(false);
        cancelButton.setEnabled(AbstractHttpRequestDesktopPanel.this.submit != null);
        return true;
    }

    public void afterSubmit(Submit submit, SubmitContext context) {
        if (submit.getRequest() != request) {
            return;
        }

        Status status = submit.getStatus();
        HttpResponse response = (HttpResponse) submit.getResponse();
        if (status == Status.FINISHED || status == Status.ERROR) {
            request.setResponse(response, context);
        }

        if (hasClosed) {
            request.removeSubmitListener(this);
            return;
        }

        cancelButton.setEnabled(false);
        setEnabled(true);

        String message;
        String infoMessage;
        String requestName = request.getOperation() == null ? request.getName() : request.getOperation().getInterface()
                .getName()
                + "." + request.getOperation().getName() + ":" + request.getName();

        if (status == Status.CANCELED) {
            message = "CANCELED";
            infoMessage = "[" + requestName + "] - CANCELED";
        } else {
            if (status == Status.ERROR || response == null) {
                message = "Error getting response; " + submit.getError();
                infoMessage = "Error getting response for [" + requestName + "]; " + submit.getError();
            } else {
                long attchmentsSize = 0;
                if (response.getAttachments().length > 0) {
                    for (Attachment att : response.getAttachments()) {
                        attchmentsSize += att.getSize();
                    }
                }
                message = "response time: " + response.getTimeTaken() + "ms ("
                        + (response.getContentLength() + attchmentsSize) + " bytes)";
                infoMessage = "Got response for [" + requestName + "] in " + response.getTimeTaken() + "ms ("
                        + (response.getContentLength() + attchmentsSize) + " bytes)";

                if (!splitButton.isEnabled()) {
                    requestTabs.setSelectedIndex(1);
                }

                responseEditor.requestFocus();
            }
        }

        logMessages(message, infoMessage);

        if (getModelItem().getSettings().getBoolean(UISettings.AUTO_VALIDATE_RESPONSE)) {
            responseEditor.getSourceEditor().validate();
        }

        AbstractHttpRequestDesktopPanel.this.submit = null;
    }

    protected void logMessages(String message, String infoMessage) {
        log.info(infoMessage);
        statusBar.setInfo(message);
    }

    public boolean onClose(boolean canCancel) {
        if (canCancel) {
            if (submit != null && submit.getStatus() == Submit.Status.RUNNING) {
                Boolean retVal = UISupport.confirmOrCancel("Cancel request before closing?", "Closing window");
                if (retVal == null) {
                    return false;
                }

                if (retVal && submit.getStatus() == Submit.Status.RUNNING) {
                    submit.cancel();
                }

                hasClosed = true;
            } else {
                request.removeSubmitListener(this);
            }
        } else if (submit != null && submit.getStatus() == Submit.Status.RUNNING) {
            submit.cancel();
            hasClosed = true;
        } else {
            request.removeSubmitListener(this);
        }

        request.removePropertyChangeListener(this);
        requestEditor.saveDocument(false);

        //		if( responseEditor != null )
        //			responseEditor.getParent().remove( responseEditor );

        requestEditor.getParent().remove(requestEditor);
        requestSplitPane.removeAll();

        return release();
    }

    @Override
    protected boolean release() {
        endpointsModel.release();
        requestEditor.release();

        if (responseEditor != null) {
            responseEditor.release();
        }

        return super.release();
    }

    public boolean dependsOn(ModelItem modelItem) {
        return request.dependsOn(modelItem);
    }

    private final class ChangeToTabsAction extends AbstractAction {
        public ChangeToTabsAction() {
            putValue(Action.SMALL_ICON, UISupport.createImageIcon("/toggle_tabs.gif"));
            putValue(Action.SHORT_DESCRIPTION, "Toggles to tab-based layout");
        }

        public void actionPerformed(ActionEvent e) {
            if (splitButton.isEnabled()) {
                splitButton.setEnabled(false);
                showTabbedView(responseHasFocus);
            } else {
                int selectedIndex = requestTabs.getSelectedIndex();

                splitButton.setEnabled(true);
                removeContent(requestTabPanel);
                setContent(requestSplitPane);
                requestSplitPane.setTopComponent(requestEditor);
                if (responseEditor != null) {
                    requestSplitPane.setBottomComponent(responseEditor);
                }
                requestSplitPane.setDividerLocation(0.5);

                if (selectedIndex == 0 || responseEditor == null) {
                    requestEditor.requestFocus();
                } else {
                    responseEditor.requestFocus();
                }
            }

            revalidate();
        }
    }

    private void showTabbedView(boolean respFocus) {
        removeContent(requestSplitPane);
        setContent(requestTabPanel);
        requestTabs.addTab("Request", requestEditor);

        if (responseEditor != null) {
            requestTabs.addTab("Response", responseEditor);
        }

        if (respFocus) {
            requestTabs.setSelectedIndex(1);
            requestEditor.requestFocus();
        }
    }

    public void focusResponseInTabbedView(boolean respFocus) {
        showTabbedView(respFocus);
        getResponseEditor().selectView(2);
    }

    public void setContent(JComponent content) {
        add(content, BorderLayout.CENTER);
    }

    public void removeContent(JComponent content) {
        remove(content);
    }

    protected void onSubmit() {
        if (submit != null && submit.getStatus() == Submit.Status.RUNNING) {
            if (UISupport.confirm("Cancel current request?", "Submit Request")) {
                submit.cancel();
            } else {
                return;
            }
        }

        try {
            submit = doSubmit();
        } catch (SubmitException e1) {
            SoapUI.logError(e1);
        }
    }

    protected void onCancel() {
        if (submit == null) {
            return;
        }

        cancelButton.setEnabled(false);
        submit.cancel();
        setEnabled(true);
        submit = null;
    }

    public boolean isHasClosed() {
        return hasClosed;
    }

    protected void enableEndpointCombo(final JComboBox endpointCombo, WsdlProject project) {
        if (project.isEnvironmentMode()) {
            endpointCombo.setEnabled(false);
        } else {
            endpointCombo.setEnabled(true);
        }
    }

}
